package com.tsd.core.utils;


import com.tsd.core.constants.Constants;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @ClassName: FieldUtils
 * @Description: TODO
 * @Author: Hillpool
 * @Date: 2022/4/15 16:16
 * @Version: 1.0
 */
public class FieldUtils {

    /**
     * 反射判断对象属性是否存在
     *
     * @param object
     * @param fieldName
     */
    public static boolean isFieldExist(Object object, String fieldName) {
        if (object == null) {
            return false;
        }
        //获取这个类的所有属性
        List<Field> fieldList = new ArrayList<>();
        Class<?> tempClass = object.getClass();
        while (tempClass != null) {
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
            tempClass = tempClass.getSuperclass();
        }
        //循环遍历所有的fields
        List<String> list = new ArrayList<>();
        for (Field value : fieldList) {
            list.add(value.getName());
        }
        return list.contains(fieldName);
    }

    /**
     * 反射取值
     *
     * @param object
     * @param fieldName
     */
    public static Field getField(Object object, String fieldName) {
        if (object == null) {
            return null;
        }
        //获取这个类的所有属性
        List<Field> fieldList = new ArrayList<>();
        Class<?> tempClass = object.getClass();
        while (tempClass != null) {
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
            tempClass = tempClass.getSuperclass();
        }
        for (Field value : fieldList) {
            if (value.getName().equalsIgnoreCase(fieldName)) {
                return value;
            }
        }
        return null;
    }

    /**
     * 反射取值
     *
     * @param object
     * @param fieldName
     */
    public static Object getFieldValue(Object object, String fieldName) {
        //获取这个类的所有属性
        Field value = getField(object, fieldName);
        if (value != null) {
            try {
                value.setAccessible(true);
                return value.get(object);
            } catch (IllegalAccessException ignored) {
            }
        }
        return null;
    }

    /**
     * 反射取值
     *
     * @param object
     * @param fieldName
     * @param splitRegex
     */
    public static Object getFieldValue(Object object, String fieldName, String splitRegex) {
        String[] fields = fieldName.split(splitRegex);
        if (fields.length > 1) {
            Object obj = getFieldValue(object, fields[0]);
            String replaceStr = fieldName.replace(fields[0], "").replaceFirst(splitRegex, "");
            return getFieldValue(obj, replaceStr, splitRegex);
        }
        return getFieldValue(object, fieldName);
    }

    /**
     * 反射赋值
     *
     * @param object
     * @param fieldName
     * @param value
     * @param overWrite 非空是否赋值
     */
    public static void setFieldValue(Object object, String fieldName, Object value, boolean overWrite) {
        if (object == null) {
            return;
        }
        if (isFieldExist(object, fieldName)) {
            try {
                Field field = getField(object, fieldName);
                if (field != null) {
                    field.setAccessible(true);
                    if (overWrite) {
                        field.set(object, value);
                    } else {
                        Object oldValue = field.get(object);
                        if (HlpUtils.isEmpty(oldValue)) {
                            field.set(object, value);
                        }
                    }
                }
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * 反射赋值
     *
     * @param object
     * @param fieldName
     * @param value
     * @param overWrite  非空是否赋值
     * @param splitRegex
     */
    @SuppressWarnings("unchecked")
    public static void setFieldValue(Object object, String fieldName, Object value, boolean overWrite, String splitRegex) {
        String[] fields = fieldName.split(splitRegex);
        if (fields.length > 1) {
            Object obj = getFieldValue(object, fields[0]);
            String replaceStr = fieldName.replaceFirst(fields[0], "").replaceFirst(splitRegex, "");
            String[] strings = fields[1].split("@");
            if (strings.length > 1) {
                replaceStr = replaceStr.replaceFirst(strings[0], "").replaceFirst("@", "");
            }
            if (obj instanceof List) {
                List<Object> list = (List<Object>) obj;
                for (Object o : list) {
                    setFieldValue(o, replaceStr, value, overWrite, splitRegex);
                }
            } else {
                setFieldValue(obj, replaceStr, value, overWrite, splitRegex);
            }
            setFieldValue(object, fields[0], obj, true);
            return;
        }
        setFieldValue(object, fieldName, value, overWrite);
    }

    public static void clearField(Object object, String... fields) {
        if (object == null || fields == null) {
            return;
        }
        for (String field : fields) {
            String[] fs = field.split(",");
            if (fs.length == 0) {
                continue;
            }
            for (String s : fields) {
                setFieldValue(object, s, null, true, "\\.");
            }
        }
    }

    public static void clearField(Object object, List<String> fields) {
        if (object == null || HlpUtils.isEmptyList(fields)) {
            return;
        }
        for (String field : fields) {
            String[] fs = field.split(",");
            for (String s : fs) {
                setFieldValue(object, s, null, true, "\\.");
            }
        }
    }

    /**
     * 复制值
     * 属性命名方式有3种：基本属性（linker_name）、类属性（baseInvoiceInfo.entity_phone）、分录属性（detail_list.id@price）
     *
     * @param source 源数据
     * @param target 目标数据
     * @param fields 属性列表
     */
    @SuppressWarnings("unchecked")
    public static void copyFieldValue(Object source, Object target, List<String> fields) {
        if (source == null || target == null || HlpUtils.isEmptyList(fields)) {
            return;
        }
        for (String field : fields) {
            // 判断是否类属性或者分录属性
            String[] fs = field.split("\\.");
            // fs 基本属性（["linker_name"]）、类属性（["baseInvoiceInfo", "entity_phone"]）、分录属性（["detail_list", "id@price"]）
            if (fs.length > 1) {
                // 判断是否分录属性（属性是否存在@字符）
                Object sourceObj = getFieldValue(source, fs[0]);
                String[] strings = fs[1].split("@");
                // strings 类属性（["entity_phone"]）、分录属性（["id", "price"]）
                if (strings.length > 1 && sourceObj instanceof List) {
                    // 分录属性复制处理 detail_list.id@price
                    // 字符@前属性为分录标识，即strings[0]
                    // 字符@后属性为需要复制的分录属性名，即strings[1]
                    Object targetObj = getFieldValue(target, fs[0]);
                    List<Object> sourceList = (List<Object>) sourceObj;
                    List<Object> targetList = (List<Object>) targetObj;
                    if (HlpUtils.isEmptyList(sourceList) || HlpUtils.isEmptyList(targetList)) {
                        continue;
                    }
                    // 获取需要复制的分录属性名：price
                    String replaceStr = field.replaceFirst(fs[0], "").replaceFirst("\\.", "");
                    replaceStr = replaceStr.replaceFirst(strings[0], "").replaceFirst("@", "");
                    for (Object sDetail : sourceList) {
                        // 获取源数据分录标识属性的值
                        Object sKeyValue = getFieldValue(sDetail, strings[0]);
                        if (sKeyValue == null) {
                            continue;
                        }
                        for (Object tDetail : targetList) {
                            // 获取目标数据分录标识属性的值
                            Object tKeyValue = getFieldValue(tDetail, strings[0]);
                            if (tKeyValue == null) {
                                continue;
                            }
                            // 判断是否相同，相同则复制数据
                            if (sKeyValue.equals(tKeyValue)) {
                                copyFieldValue(sDetail, tDetail, Collections.singletonList(replaceStr));
                            }
                        }
                    }
                    setFieldValue(target, fs[0], targetList, true);
                    // 分录属性复制处理完成，跳过本次循环,进入下一个循环
                    continue;
                }
            }
            // 基本属性、类属性复制
            // 从源数据种获取字段field的值复制到目标数据的字段field
            Object value = getFieldValue(source, field, "\\.");
            setFieldValue(target, field, value, true, "\\.");
        }
    }
}
